#include <iostream>
#include <iomanip>
#include<unistd.h>

#include "env.h"
#include "log.h"


namespace qtch {


static Logger::ptr logger = QTCH_LOG_NAME("system");

bool Env::init(int argc,char** argv) {
    char path[1024];
    char link[1024];
    sprintf(link,"/proc/%d/exe",getpid());
    readlink(link,path,sizeof(path));

    m_exe = path;
    auto pos = m_exe.find_last_of('/');
    m_cwd = m_exe.substr(0,pos)+"/";
    m_program = argv[0];
    pos = m_program.find_last_of("/");
    m_program = m_program.substr(pos+1);
    m_exe = m_cwd + m_program;

    const char* nowKey = nullptr;
    for(int i = 1;i < argc; ++i){
        if(argv[i][0] == '-'){
            if(nowKey){
                add(nowKey+1, "");
            }
            if(strlen(argv[i])==1){
                QTCH_LOG_ERROR(logger) << "invalid arg, arg key could't be null";
                return false;
            }
            nowKey = argv[i];
        }else{
            if(nowKey){
                add(nowKey+1,argv[i]);
                nowKey = nullptr;
            }else {
                QTCH_LOG_ERROR(logger) << "invalid arg idx=" << i << " arg=" << argv[i];
                return false;
            }
        }
    }
    if(nowKey){
        add(nowKey+1,"");
    }
    
    return true;
    
}

void  Env::add(const std::string& key, const std::string& val) {
    RWMutexType::WriteLock lock(m_mutex);
    m_args[key] = val;
}

bool  Env::has(const std::string& key) {
    RWMutexType::ReadLock lock(m_mutex);
    auto it = m_args.find(key);
    return it != m_args.end();
}

void  Env::del(const std::string& key) {
    RWMutexType::WriteLock lock(m_mutex);
    m_args.erase(key);
}

std::string  Env::get(const std::string& key, const std::string& default_val) {
    RWMutexType::ReadLock lock(m_mutex);
    auto it = m_args.find(key);
    if(it == m_args.end()){
        return default_val;
    }
    return m_args[key];
}

void  Env::addHelp(const std::string& key,const std::string& desc) {
    if(removeHelp(key)){
        QTCH_LOG_WARN(logger) << "addHelp repeat key=" << key << " desc=" << desc;
    }
    RWMutexType::WriteLock lock(m_mutex);
    m_help.push_back(std::make_pair(key,desc));
}

bool  Env::removeHelp(const std::string& key) {
    RWMutexType::WriteLock lock(m_mutex);
    bool flag = false;
    for(auto it = m_help.begin(); it!=m_help.end();){
        if(it->first == key){
            it == m_help.erase(it);
            flag = true;
        }
        else {
            it++;
        }
    }
    return flag;
}

void  Env::printfHelp() {
    RWMutexType::ReadLock lock(m_mutex);
    std::cout << "Usage:" << m_program << "[options]" << std::endl;
    for(auto& i : m_help){
        std::cout << std::setw(10) << "-" << i.first << " : " << i.second << std::endl;
    }

}

const std::string  Env::getEnv(const std::string& key, const std::string& default_val) {
    char * v = getenv(key.c_str());
    if(v == nullptr){
        return default_val;
    }
    std::string result(v);
    return result;

}

bool  Env::setEnv(const std::string& key, const std::string& val) {
    return !setenv(key.c_str(), val.c_str(), 1);
}

std::string  Env::getAbsolutePath(const std::string& path) const {
    if(path.empty()){
        return m_cwd;
    }
    if(path[0]=='/'){
        return path;
    }
    return m_cwd + path;
}

std::string  Env::getAbsoluteWorkPath(const std::string& path) const {
    // 等待有需求再完善 22.9.26 waitch
    return getAbsolutePath(path);
}

std::string  Env::getConfigPath() {
    return getAbsolutePath(get("c","conf"));
}


}